<?php
/**
 * Created by PhpStorm.
 * User: lih
 * Date: 2017/11/7
 * Time: 22:26
 */

namespace common\utils;

require_once(dirname(__FILE__).'/../libs/simplehtmldom/simple_html_dom.php');
require_once('Utils.php');

use Yii;

class HtmlSpider
{

    public function load($rule)
    {
        $result = array();
        try {
            if ($rule !== null) {
                $url = $rule['host'] . $rule['path'];
                $html = file_get_html($url);
                $listDom = $this->findElementsByXpath($html, $rule['list']['xpath']);
                if(is_array($listDom)) {
                    $listResult = array();
                    $attrList = $rule['list']['attrs'];
                    foreach($listDom as $item) {
                        $itemResult = array();
                        foreach($attrList as $attr) {
                            $val = $this->findAttrByXpath($item, $attr['xpath'], $url);
                            if($val !== null) {
                                $itemResult[$attr['name']] = $val;
                            }
                        }
                        $listResult[] = $itemResult;
                    }
                    $result['list'] = $listResult;
                }

                $url = @$rule['detail']['testUrl'];
                if($url !== null) {
                    $html = file_get_html($url);
                    $listDom = $this->findElementsByXpath($html, $rule['detail']['xpath']);
                    if(is_array($listDom)) {
                        $listResult = array();
                        $attrImg = $rule['detail']['img'];
                        foreach($listDom as $item) {
                            $val = $this->findAttrByXpath($item, $attrImg, $url);
                            if($val !== null) {
                                $listResult[] = $val;
                            }
                        }
                        $result['detail']['imgs'] = $listResult;
                    }

                    if(@$rule['detail']['nextPage'] !== null) {
                        $result['detail']['nextPage'] = $this->findAttrByXpath($html, $rule['detail']['nextPage'], $url);
                    }
                }
            }
        } catch(Exception $e) {
            Utils::log('HtmlSpider load exception: ' . $e->getMessage());
        }
        return $result;
    }

    /**
     * @param \simple_html_dom $dom
     * @param string $xpath
     */
    private function findElementsByXpath($dom, $xpath)
    {
        $result = null;
        $ruleList = explode('@', $xpath);
        if ($ruleList !== null) {
            for ($i = 0; $i < count($ruleList); $i += 2) {
                $rule = $ruleList[$i];
                $ruleNext = null;
                if($i + 1 < count($ruleList)) {
                    $ruleNext = $ruleList[$i + 1];
                }
                if($rule != null && strlen($rule) > 0) {
                    if($ruleNext !== null) {
                        $dom = $dom->find($rule, intval($ruleNext));
                    } else {
                        $result = $dom->find($rule);
                        break;
                    }
                }
                if($dom === null) {
                    break;
                }
            }
        }
        return $result;
    }

    /**
     * @param \simple_html_dom $dom
     * @param string $xpath
     */
    private function findAttrByXpath($dom, $xpath, $urlTarget)
    {
        $result = null;
        $ruleList = explode('@', $xpath);
        if ($ruleList !== null) {
            for ($i = 0; $i < count($ruleList); $i += 2) {
                $rule = $ruleList[$i];
                $ruleNext = null;
                if($i + 1 < count($ruleList)) {
                    $ruleNext = $ruleList[$i + 1];
                }
                if($rule != null && strlen($rule) > 0) {
                    if($ruleNext !== null) {
                        $dom = $dom->find($rule, intval($ruleNext));
                    } else {
                        if(0 === strpos($rule, 'abs:')) {
                            $rule = substr($rule, strlen('abs:'));
                            $result = $dom->getAttribute($rule);
                            return $this->fillAbsPath($urlTarget, $result);
                        } else {
                            $result = $dom->getAttribute($rule);
                        }
                        break;
                    }
                }
                if($dom === null) {
                    break;
                }
            }
        }
        return $result;
    }

    private function fillAbsPath($urlTarget, $linkChild) {
        if(strpos($linkChild, '://') > 0) {
            return $linkChild;
        }
        if(0 === strpos($linkChild, '/')) {
            $urlParse = parse_url($urlTarget);
            return $urlParse['scheme'] . '://' . $urlParse['host'] . $linkChild;
        }
        $urlPath = $urlTarget;
        if(strrpos($urlPath, '/') > 0) {
            $urlPath = substr($urlPath, 0, strrpos($urlPath, '/'));
        }
        return $urlPath . '/' . $linkChild;
    }
}